import org.springframework.beans.factory.BeanFactoryAware
import org.springframework.beans.factory.BeanFactory
import org.springframework.beans.BeansException
import org.apache.commons.logging.LogFactory
/**
 * use to extract rss feeds
 */
class FetchFeedProcess implements Runnable, BeanFactoryAware {
    def static log = LogFactory.getLog(FetchFeedProcess.class)
  
    def resource
    def fetchService
    def indexTaskExecutor
    def beanFactory
    def sessionFactory
    void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory
    }
    def index(entry) {
        def process = beanFactory.getBean('indexProcess')
        process.entry = entry
        indexTaskExecutor.execute(process)      
    }
  
    public void run() {
        if (resource.feedUrl) {
            log.debug "begin fetch feed ${resource.feedUrl}"
            def feeds = fetchService.fetchFeeds(resource.feedUrl)
            log.debug "feed size = ${feeds.entries.size}"
            feeds.entries.each { feed ->
                def link = feed.link
                // check feedburner
                def mod = feed.getModule('http://rssnamespace.org/feedburner/ext/1.0')
                if (mod != null) {
                    link = mod.origLink
                }

                def publishedDate = feed.publishedDate
                if (publishedDate == null) {
                    publishedDate = feed.updatedDate // exteen has no publishedDate
                }
                def content
                if (feed.contents) {
                    content = feed.contents[0].value
                } else {
                    content = feed.description.value
                }

                def tags = ''
                if (feed.categories) {
                    tags = feed.categories.collect {it.name}.join(',')
                }

                def entry = Entry.findByLink(link)

                def shouldSave = false
                if (entry) {
                    // bug? why both publishedDate sometime different by 1-2 millisec
                    // so we can't compare them directly
                    if (publishedDate.getTime() - entry.publishedDate.getTime() > 1000) {
                        entry.content = content
                        entry.tags = tags
                        entry.publishedDate = publishedDate
                        entry.lastUpdated = new java.sql.Timestamp(System.currentTimeMillis())
                        shouldSave = true
                    }
                } else {
                    entry = new Entry(link: link,
                                      title: feed.title,
                                      content: content,
                                      tags: tags,
                                      publishedDate: publishedDate,
                                      lastUpdated: new java.sql.Timestamp(System.currentTimeMillis()),
                                      resource: resource) 
                    shouldSave = true
                }
                if (shouldSave) {
                    if (entry.validate()) {
                        try {
                            Entry.withTransaction { status ->
                                entry.save()
                                log.debug ("---------save success----------")
                            }
                            index(entry)
                        } catch (org.springframework.jdbc.UncategorizedSQLException e) {
                            log.error ("=========== error for this content ===========")
                            log.error (entry.link)
                            log.error (entry.content)
                            log.error ("----------------------------------------------")
                        }
                    } else {
                        entry.errors.allErrors.each {
                            log.error it
                        }
                    }
                } else {
                    log.debug ("no update for this entry ${entry.id}");
                }
            } // end each loop
            // update resource.lastUpdated
            Resource.withTransaction { status ->
                resource.lastUpdated = new java.sql.Timestamp(System.currentTimeMillis())
                // coz resource object fetch by different session so we use merge
                // instead of resource.save()
                sessionFactory.currentSession.merge(resource)
            }
        }
    }
}